package com.hzncc.flowable_diboot.config;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.diboot.core.util.BeanUtils;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

/**
 * 默认排序拦截器
 * 添加默认排序方式 create_time desc
 *
 * @author 陈广煜
 * @date 2024/6/24
 */
@Log
@Slf4j
public class BaseOrderByInterceptor extends JsqlParserSupport implements InnerInterceptor {

    private static List<String> COLUMNS = new ArrayList<String>() {
        {
            this.add("update_time");
        }
    };

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = mpSh.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        if (sct != SqlCommandType.SELECT) {
            // 不是查询操作则直接跳过，不做任何操作
            return;
        }
        PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
        mpBs.sql(parserMulti(mpBs.sql(), mpBs.parameterObject()));
    }


    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        // 1. 解析SQL
        PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
        List<OrderByElement> originOrderList = plainSelect.getOrderByElements();
        List<OrderByElement> clonedOriginOrder = null;
        if (originOrderList != null && originOrderList.size() > 0) {
            // 创建副本，然后删除原有排序规则
            clonedOriginOrder = copyToList(originOrderList);
            originOrderList.clear();
        }

        // 2. 向 plainSelect 中添加自定义排序规则
        addCustomizeSortColumns(plainSelect);

        // 3. 添加SQL的原始排序规则 - 追加到末尾
        if (clonedOriginOrder != null && clonedOriginOrder.size() > 0) {
            plainSelect.addOrderByElements(clonedOriginOrder);
        }

    }

    private <T> List<T> copyToList(List<T> originOrderList) {
        List<T> result = new ArrayList<>();
        for (T t : originOrderList) {
            result.add(BeanUtils.cloneBean(t));
        }
        return result;
    }

    /**
     * 添加自定义排序规则
     *
     * @param plainSelect 明文
     * @author weiheng
     **/
    private void addCustomizeSortColumns(PlainSelect plainSelect) {

        // 获取主表别名
        FromItem fromItem = plainSelect.getFromItem();
        Alias alias = fromItem.getAlias();
        String primaryTableAlias = null;
        if (!ObjectUtils.isEmpty(alias)) {
            primaryTableAlias = alias.getName();
        }
        List<OrderByElement> orders = new ArrayList<>();
        for (String col : COLUMNS) {
            OrderByElement order = new OrderByElement();
            order.setAsc(false);
            order.setExpression(new Column(primaryTableAlias == null ? col : primaryTableAlias + "." + col));
        }
        plainSelect.addOrderByElements(orders);

    }

}
